package logger

import (
	"time"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var zapLogger *zap.Logger

// Option configures a logger.
type Option func(*Logger)

type File struct {
	FilePath     string        // 文件记录路径
	MaxAge       time.Duration // 保存时长
	MaxBackups   int           // 日志文件最多保存多少个备份
	Compress     bool          // 是否压缩
	MaxSize      int32         // 每个日志文件保存的大小 单位:M
	RotationTime time.Duration // 轮询周期，最小一分钟
}
type Config struct {
	Level zapcore.Level // 错误级别
	Debug bool          // 是否输出打印
	Field []string      // 补充字段
}

type Logger struct {
	*zap.SugaredLogger         // Logger
	config             *Config // 基础配置
	file               *File   // 文件记录
}

func InitLogger(options ...Option) *Logger {
	// 赋默认值
	l := &Logger{
		config: &Config{
			Level: zap.DebugLevel,
			Debug: false,
		},
		file: &File{
			FilePath:     "",
			MaxAge:       time.Hour * 24 * 7,
			MaxBackups:   30,
			Compress:     false,
			MaxSize:      128,
			RotationTime: time.Minute * 5,
		},
	}
	for _, o := range options {
		o(l)
	}

	encoderConfig := zapcore.EncoderConfig{
		MessageKey:     "msg",   // 输入信息的key名
		LevelKey:       "level", // 输出日志级别的key名
		TimeKey:        "time",  // 输出时间的key名
		NameKey:        "logger",
		CallerKey:      "caller",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,      // 每行的分隔符。基本zapcore.DefaultLineEnding 即"\\n"
		EncodeLevel:    zapcore.LowercaseLevelEncoder,  // 基本zapcore.LowercaseLevelEncoder。将日志级别字符串转化为小写
		EncodeTime:     zapcore.ISO8601TimeEncoder,     // 输出的时间格式
		EncodeDuration: zapcore.SecondsDurationEncoder, // 一般zapcore.SecondsDurationEncoder,执行消耗的时间转化成浮点型的秒
		EncodeCaller:   zapcore.ShortCallerEncoder,     // 一般zapcore.ShortCallerEncoder，以包/文件:行号 格式化调用堆栈
		EncodeName:     zapcore.FullNameEncoder,
	}
	// 设置日志级别
	atomicLevel := zap.NewAtomicLevel()
	atomicLevel.SetLevel(zap.DebugLevel)
	var (
		encoder = zapcore.NewJSONEncoder(encoderConfig)
		cores   = make([]zapcore.Core, 0)
		opts    = make([]zap.Option, 0)
		// fs      = make([]zapcore.Field, 0)
	)
	core := zapcore.NewCore(
		encoder,
		zapcore.NewMultiWriteSyncer(),
		atomicLevel,
	)

	cores = append(cores, core)
	// 如果是开发环境，同时在控制台上也输出
	if l.config.Debug {
		cores = append(cores, l.debugCore(encoder))
	}
	if l.file.FilePath != "" {
		cores = append(cores, l.fileCore(encoder))
	}
	newCore := zapcore.NewTee(cores...)

	// 开启开发模式，堆栈跟踪
	opts = append(opts, zap.AddCaller(), zap.AddCallerSkip(1))
	// 开启文件及行号
	opts = append(opts, zap.Development())
	// 设置初始化字段
	// fs = append(fs, zap.String("", ""))
	// if len(fs) > 0 {
	// 	opts = append(opts, zap.Fields(fs...))
	// }
	// 构造日志
	zapLogger = zap.New(newCore, opts...)
	defer zapLogger.Sync() // zap底层 API 可以设置缓存，所以一般使用defer logger.Sync()将缓存同步到文件中
	l.SugaredLogger = zapLogger.Sugar()
	return l
}

func SetLevel(lvl string) Option {
	return func(l *Logger) {
		l.config.Level = zapLevel(lvl)
	}
}

func SetFilePath(p string) Option {
	return func(l *Logger) {
		l.file.FilePath = p
	}
}

func SetDebug(b bool) Option {
	return func(l *Logger) {
		l.config.Debug = b
	}
}

func SetField(f []string) Option {
	return func(l *Logger) {
		l.config.Field = f
	}
}

func zapLevel(l string) zapcore.Level {
	switch l {
	case "debug":
		return zapcore.DebugLevel
	case "info":
		return zapcore.InfoLevel
	case "warn":
		return zapcore.WarnLevel
	case "error":
		return zapcore.ErrorLevel
	case "fatal":
		return zapcore.FatalLevel
	default:
		return zapcore.DebugLevel
	}
}
